﻿using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using WebApp.Entities;
using WebApp.Models;

namespace WebApp.Services
{
    /// <summary>
    /// 
    /// </summary>
    public class Socketor
    {

        private readonly ILogger<Socketor> _logger;
        /// <summary>
        /// Socket消息发送类
        /// </summary>
        /// <param name="logger"></param>
        public Socketor(ILogger<Socketor> logger)
        {
            _logger = logger;
        }
        ///// <summary>
        ///// 是否为空数据
        ///// </summary>
        ///// <param name="byteMessage"></param>
        ///// <returns></returns>
        //private bool IsWhiteOrEmpty(this byte[] byteMessage)
        //{
        //    bool istrue = true;
        //    foreach (var b in byteMessage)
        //    {
        //        if (b != 0)
        //        {
        //            istrue = false;
        //            break;
        //        }
        //    }
        //    return istrue;
        //}
        private bool getTempOrNot(byte[] byteMessage)
        {
            int count = 0;
            for (int i = 0; i < 50; i++)
            {
                if (byteMessage[i].ToString("X2") != "00")
                {
                    count += 1;
                    break;
                }
            }
            if (count == 0)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
        private void LogDebug(string title, byte[] bytes)
        {
            string order = "";
            for (int i = 0; i < bytes.Length; i++)
            {
                order += bytes[i].ToString("X2") + " ";
            }
            _logger.LogDebug($"\r\n{title}\r\n{order}");
        }
        private void LogError(string title, byte[] bytes)
        {
            string order = "";
            for (int i = 0; i < bytes.Length; i++)
            {
                order += bytes[i].ToString("X2") + " ";
            }
            _logger.LogError($"\r\n{title}\r\n{order}");
        }
        /// <summary>
        /// 执行发送
        /// </summary>
        /// <param name="_socket"></param>
        /// <param name="collectorcode"></param>
        /// <param name="metercode"></param>
        /// <param name="command"></param>
        /// <param name="pwd"></param>
        /// <returns></returns>
        public PowerCmdResult Send(Socket _socket, string collectorcode, string metercode, string command, string pwd)
        {
            var result = new PowerCmdResult() { Result = false, Message = "", Power = 0, MeterCode = metercode };

            try
            {
                if (command.Equals("C03C", StringComparison.OrdinalIgnoreCase))//断电控制，无条件断电
                {
                    byte[] bytes = CartPower("C03C", metercode, pwd);

                    LogDebug($"发 C03C 采集器 {collectorcode} 电表 {metercode} ", bytes);

                    _socket.Send(bytes);

                    byte[] byteMessage = new byte[100];
                    int len = 0;
                    while (true)
                    {
                        byte[] temp = new byte[30];
                        var l = _socket.Receive(temp);
                        for (int i = 0; i < l; i++)
                        {
                            byteMessage[i + len] = temp[i];
                        }
                        len += l;
                        //_logger.LogInformation($"收 9010 分批 {l}, {string.Join(" ", Byte2String(temp.Take(l).ToArray()))}");

                        if (temp[l - 1].ToString("X2") == "16")
                            break;
                    }


                    LogDebug($"收 C03C 采集器 {collectorcode} 电表 {metercode} ", byteMessage.Take(len).ToArray());


                    if (byteMessage[12].ToString("X2") == "84")
                    {
                        result.Result = true;
                    }
                    else
                    {
                        //result = "下发失败！【" + byteMessage[13].ToString("X2") + byteMessage[14].ToString("X2") + byteMessage[15].ToString("X2") + "】";
                        LogError($"下发 C03C 失败 采集器 {collectorcode} 电表 {metercode}", byteMessage.Take(len).ToArray());
                        result.Message = $"收到内容：{string.Join(" ", Byte2String(byteMessage.Take(len).ToArray()))}";
                    }
                }
                else if (command.Equals("C03D", StringComparison.OrdinalIgnoreCase)) //无条件通电
                {
                    byte[] bytes = UpPower("C03D", metercode, pwd);

                    LogDebug($"发 C03D 采集器 {collectorcode} 电表 {metercode}", bytes);

                    _socket.Send(bytes);

                    byte[] byteMessage = new byte[100];
                    int len = 0;
                    while (true)
                    {
                        byte[] temp = new byte[30];
                        var l = _socket.Receive(temp);
                        for (int i = 0; i < l; i++)
                        {
                            byteMessage[i + len] = temp[i];
                        }
                        len += l;
                        //_logger.LogInformation($"收 9010 分批 {l}, {string.Join(" ", Byte2String(temp.Take(l).ToArray()))}");

                        if (temp[l - 1].ToString("X2") == "16")
                            break;
                    }


                    LogDebug($"收 C03D 采集器 {collectorcode} 电表 {metercode}", byteMessage.Take(len).ToArray());


                    if (byteMessage[12].ToString("X2") == "84")
                    {
                        result.Result = true;//result = "下发成功";
                    }
                    else
                    {
                        //result = "下发失败！【" + byteMessage[13].ToString("X2") + byteMessage[14].ToString("X2") + byteMessage[15].ToString("X2") + "】";
                        LogError($"下发 C03D 失败 采集器{collectorcode}_电表{metercode}", byteMessage.Take(len).ToArray());
                        result.Message = $"收到内容：{string.Join(" ", Byte2String(byteMessage.Take(len).ToArray()))}";
                    }
                }
                else if (command.Equals("9010", StringComparison.OrdinalIgnoreCase))
                {
                    byte[] bytes = CopyRemainPower("9010", metercode, pwd);

                    LogDebug($"发 9010 采集器 {collectorcode} 电表 {metercode}", bytes);

                    _socket.Send(bytes);

                    byte[] byteMessage = new byte[100];
                    int len = 0;
                    while (true)
                    {
                        byte[] temp = new byte[30];
                        var l = _socket.Receive(temp);
                        for (int i = 0; i < l; i++)
                        {
                            byteMessage[i + len] = temp[i];
                        }
                        len += l;
                        //_logger.LogInformation($"收 9010 分批 {l}, {string.Join(" ", Byte2String(temp.Take(l).ToArray()))}");

                        if (temp[l - 1].ToString("X2") == "16")
                            break;
                    }

                    LogDebug($"收 9010 采集器 {collectorcode} 电表 {metercode}", byteMessage.Take(len).ToArray());

                    if (byteMessage[12].ToString("X2") == "81")
                    {
                        result.Result = true;// result = "下发成功";
                        var (MeterCode, Power) = ReadElectricity(byteMessage);
                        result.Power = Power;
                        result.MeterCode = MeterCode;
                    }
                    else
                    {
                        //result = "下发失败【" + byteMessage[13].ToString("X2") + byteMessage[14].ToString("X2") + byteMessage[15].ToString("X2") + "】";
                        LogError($"下发 9010 失败 采集器 {collectorcode} 电表 {metercode}", byteMessage.Take(len).ToArray());
                        result.Message = $"收到内容：{string.Join(" ", Byte2String(byteMessage.Take(len).ToArray()))}";
                    }
                }

            }
            catch (SocketException sex)
            {
                _logger.LogError(sex, $"异常 SocketException {collectorcode}" );
                result.Message = sex.Message;
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, $"异常 {collectorcode}");
                result.Message = ex.Message;
            }
            return result;
        }
        /// <summary>
        /// 抄剩余电量 和有功电量
        /// </summary>
        /// <param name="operton">操作数</param>
        /// <param name="PowerNo">电表编号</param>
        /// <param name="pwd">密码</param>
        /// <returns>byte</returns>
        public byte[] CopyRemainPower(string operton, string PowerNo, string pwd)
        {
            byte[] byteall = new byte[15];
            byte[] mo = new byte[13];
            byteall[0] = (byte)0xFE;
            mo[0] = (byte)0x00;
            byteall[1] = (byte)0x68;
            mo[1] = (byte)0x68;



            byte[] byteAddress = PowerNobyte(PowerNo);
            for (int i = 0; i < byteAddress.Length; i++)
            {
                byteall[i + 2] = byteAddress[i];
                mo[i + 2] = byteAddress[i];
            }
            byteall[8] = (byte)(0x68);
            mo[8] = (byte)(0x68);
            byteall[9] = (byte)(0x01);
            mo[9] = (byte)(0x01);
            byteall[10] = (byte)(0x02);
            mo[10] = (byte)(0x02);
            byte[] opera = getOpera(operton);

            for (int i = 0; i < opera.Length; i++)
            {
                byteall[11 + i] = opera[i];
                mo[11 + i] = opera[i];
            }

            byteall[13] = getmol(mo);

            byteall[14] = (byte)(0x16);

            return byteall;
        }
        /// <summary>
        /// 无条件通电(C03D): 
        /// 字节长度从19增长到22位
        /// @20200902
        /// </summary>
        /// <param name="operton">操作符</param>
        /// <param name="PowerNo">电表编号</param>
        /// <param name="pwd">密码</param>
        /// <returns>byte 流,19</returns>
        public byte[] UpPower(string operton, string PowerNo, string pwd)
        {
            byte[] byteall = new byte[19];
            byte[] mo = new byte[17];
            byteall[0] = (byte)0xFE;
            mo[0] = (byte)0x00;
            byteall[1] = (byte)0x68;
            mo[1] = (byte)0x68;

            byte[] byteAddress = PowerNobyte(PowerNo);
            for (int i = 0; i < byteAddress.Length; i++)
            {
                byteall[i + 2] = byteAddress[i];
                mo[i + 2] = byteAddress[i];
            }
            byteall[8] = (byte)(0x68);
            mo[8] = (byte)(0x68);
            byteall[9] = (byte)(0x04);
            mo[9] = (byte)(0x04);
            byteall[10] = (byte)(0x06);
            mo[10] = (byte)(0x06);
            byte[] opera = getOpera(operton);

            for (int i = 0; i < opera.Length; i++)
            {
                byteall[11 + i] = opera[i];
                mo[11 + i] = opera[i];
            }

            byte[] pwdbyte = pwdbyte1(pwd);

            for (int i = 0; i < pwdbyte.Length; i++)
            {
                byteall[13 + i] = pwdbyte[i];
                mo[13 + i] = pwdbyte[i];
            }

            byteall[17] = getmol(mo);

            byteall[18] = (byte)(0x16);

            //增长3位
            byte[] byteret = new byte[22];
            byteret[0] = byteret[1] = byteret[2] = byteret[3] = byteall[0];
            for (int i = 1; i < byteall.Length; i++)
            {
                byteret[i + 3] = byteall[i];
            }

            return byteret;
        }

        /// <summary>
        /// 保存抄表数据
        /// </summary>
        /// <param name="byteMessage"></param>
        private (string MeterCode, decimal Power) ReadElectricity(byte[] byteMessage)
        {
            string metercode = string.Empty;
            decimal power = 0M;
            //电表读数
            if (byteMessage[13] == (byte)(Convert.ToInt16("90", 16) + 0x33) && byteMessage[12] == (byte)(Convert.ToInt16("10", 16) + 0x33))
            {
                for (int i = 8; i >= 3; i--)
                {
                    metercode += byteMessage[i].ToString("X2");
                }

                int ff = ((byteMessage[16] - 0x33));
                var Opera1 = ff.ToString("X2");

                ff = ((byteMessage[15] - 0x33));
                Opera1 += ff.ToString("X2");

                ff = ((byteMessage[14] - 0x33));
                string Point = ff.ToString("X2");
                string strPoint = Point;
                //string Power = Opera1 + "." + strPoint;
                string Power1 = Opera1 + "." + strPoint;
                //Power.Write("电表：=====" + Power1);
                if (decimal.Parse(Power1) > 9000.00M)
                {
                    decimal temppower = decimal.Parse(Power1) - 9999.99M;
                    Power1 = temppower.ToString();
                }
                power = decimal.Parse(Power1);
            }

            //电表读数
            else if (byteMessage[17] == (byte)(Convert.ToInt16("90", 16) + 0x33) && byteMessage[16] == (byte)(Convert.ToInt16("10", 16) + 0x33))
            {
                for (int i = 12; i >= 7; i--)
                {
                    metercode += byteMessage[i].ToString("X2");
                }

                int ff = ((byteMessage[20] - 0x33));
                var Opera1 = ff.ToString("X2");

                ff = ((byteMessage[19] - 0x33));
                Opera1 += ff.ToString("X2");

                ff = ((byteMessage[18] - 0x33));
                string Point = ff.ToString("X2");
                string strPoint = Point;
                string Power1 = Opera1 + "." + strPoint;

                if (decimal.Parse(Power1) > 9000.00M)
                {
                    decimal temppower = decimal.Parse(Power1) - 9999.99M;
                    Power1 = temppower.ToString();
                }

                power = decimal.Parse(Power1);

            }

            //电表读数
            else if (byteMessage[15] == (byte)(Convert.ToInt16("90", 16) + 0x33) && byteMessage[14] == (byte)(Convert.ToInt16("10", 16) + 0x33))
            {

                for (int i = 10; i >= 5; i--)
                {
                    metercode += byteMessage[i].ToString("X2");
                }

                int ff = ((byteMessage[18] - 0x33));
                var Opera1 = ff.ToString("X2");

                ff = ((byteMessage[17] - 0x33));
                Opera1 += ff.ToString("X2");

                ff = ((byteMessage[16] - 0x33));
                string Point = ff.ToString("X2");
                string strPoint = Point;
                string Power1 = Opera1 + "." + strPoint;
                if (decimal.Parse(Power1) > 9000.00M)
                {
                    decimal temppower = decimal.Parse(Power1) - 9999.99M;
                    Power1 = temppower.ToString();
                }
                power = decimal.Parse(Power1);
            }

            else
            {
                int begin = 0;
                int end = 0;
                for (int i = 0; i < byteMessage.Length; i++)
                {
                    if ((int)byteMessage[i] == 254 && begin == 0)
                    {
                        begin = i;
                    }
                    else if ((int)byteMessage[i] == 22 && end == 0)
                    {
                        end = i;
                    }


                }

                if (end > begin)
                {
                    byte[] bytetemp = new byte[end - begin + 1];
                    int point = 0;
                    for (int j = begin; j < end; j++)
                    {
                        bytetemp[point] = byteMessage[j];
                        point++;
                    }

                    for (int i = 8; i >= 3; i--)
                    {
                        metercode += byteMessage[i].ToString("X2");
                    }

                    var Opera1 = (((byteMessage[16] - 0x33) / 16) * 10 + ((byteMessage[16] - 0x33) % 16)) * 100;
                    Opera1 += ((byteMessage[15] - 0x33) / 16) * 10 + ((byteMessage[15] - 0x33) % 16);

                    power = Opera1;
                }

            }
            return (metercode, power);
        }
        /// <summary>
        /// 无条件断电(C03C)
        /// </summary>
        /// <param name="operton">操作符</param>
        /// <param name="PowerNo">电表编号</param>
        /// <param name="pwd">密码</param>
        /// <returns>byte 流</returns>
        public byte[] CartPower(string operton, string PowerNo, string pwd)
        {
            byte[] byteall = new byte[19];
            byte[] mo = new byte[17];

            byteall[0] = (byte)0xFE;
            mo[0] = (byte)0x00;
            byteall[1] = (byte)0x68;
            mo[1] = (byte)0x68;



            byte[] byteAddress = PowerNobyte(PowerNo);
            for (int i = 0; i < byteAddress.Length; i++)
            {
                byteall[i + 2] = byteAddress[i];
                mo[i + 2] = byteAddress[i];
            }
            byteall[8] = (byte)(0x68);
            mo[8] = (byte)(0x68);
            byteall[9] = (byte)(0x04);
            mo[9] = (byte)(0x04);
            byteall[10] = (byte)(0x06);
            mo[10] = (byte)(0x06);
            byte[] opera = getOpera(operton);

            for (int i = 0; i < opera.Length; i++)
            {
                byteall[11 + i] = opera[i];
                mo[11 + i] = opera[i];
            }

            byte[] pwdbyte = pwdbyte1(pwd);

            for (int i = 0; i < pwdbyte.Length; i++)
            {
                byteall[13 + i] = pwdbyte[i];
                mo[13 + i] = pwdbyte[i];
            }

            byteall[17] = getmol(mo);

            byteall[18] = (byte)(0x16);

            //增长3位
            byte[] byteret = new byte[22];
            byteret[0] = byteret[1] = byteret[2] = byteret[3] = byteall[0];
            for (int i = 1; i < byteall.Length; i++)
            {
                byteret[i + 3] = byteall[i];
            }

            return byteret;

            //return byteall;
        }
        /// <summary>
        /// 密码加密转byte
        /// </summary>
        /// <param name="pwd">密码</param>
        /// <returns>byte</returns>
        public byte[] pwdbyte1(string pwd)
        {
            byte[] pwd1byte = new byte[4];

            pwd1byte[0] = (byte)(Convert.ToInt16(pwd.Substring(pwd.Length - 2), 16) + 0x33);
            pwd1byte[1] = (byte)(Convert.ToInt16(pwd.Substring(pwd.Length - 4, 2), 16) + 0x33);
            pwd1byte[2] = (byte)(Convert.ToInt16(pwd.Substring(pwd.Length - 6, 2), 16) + 0x33);
            pwd1byte[3] = (byte)(Convert.ToInt16(pwd.Substring(0, 2), 16) + 0x33);
            return pwd1byte;
        }
        /// <summary>
        /// 取得 从地址位后的 68开始到 校验码之前的 模 取不大于256的值
        /// </summary>
        /// <param name="all">byte[]</param>
        /// <returns>byte</returns>
        public byte getmol(byte[] all)
        {
            byte mol;
            int aa = 0;
            for (int i = 0; i < all.Length; i++)
            {

                aa += all[i];
            }
            mol = (byte)(aa % 256);
            return mol;
        }


        public byte[] getOpera(string optea)
        {
            byte[] opera = new byte[2];

            opera[0] = (byte)(Convert.ToInt16(optea.Substring(optea.Length - 2), 16) + 0x33);
            opera[1] = (byte)(Convert.ToInt16(optea.Substring(0, 2), 16) + 0x33);
            return opera;
        }

        /// <summary>
        /// 获取功率byte
        /// </summary>
        /// <param name="kw">功率（kw）</param>
        /// <returns>byte</returns>
        public byte[] getkw(string kw)
        {
            byte[] kw1 = new byte[2];
            string[] aa = kw.Split('.');

            kw1[0] = (byte)(Convert.ToInt16(aa[1], 16) + 0x33);
            kw1[1] = (byte)(Convert.ToInt16(aa[0], 16) + 0x33);
            return kw1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="bytestr"></param>
        /// <returns></returns>
        public string[] Byte2String(byte[] bytestr)
        {
            string[] strbyte = new string[bytestr.Length];
            for (int i = 0; i < bytestr.Length; i++)
            {
                strbyte[i] = bytestr[i].ToString("X2");
            }
            return strbyte;
        }

        /// <summary>
        /// 电表编号转byte
        /// </summary>
        /// <param name="PowerNo">电表编号</param>
        /// <returns>byte</returns>
        public byte[] PowerNobyte(string PowerNo)
        {
            byte[] bytePwd = new byte[PowerNo.Length / 2];
            for (int i = 0; i < PowerNo.Length / 2; i++)
            {
                bytePwd[i] = Convert.ToByte(PowerNo.Substring(PowerNo.Length - (i + 1) * 2, 2), 16);
            }
            return bytePwd;

        }
    }


}
